/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using DataModelException = System.Qizx.Api.DataModelException;
using Node = System.Qizx.Api.Node;
using XMLPullStream = System.Qizx.Api.XMLPullStream;
using XMLPushStream = System.Qizx.Api.XMLPushStream;
using CorePushBuilder = System.Qizx.Xdm.CorePushBuilder;
using FONIDataModel = System.Qizx.Xdm.FONIDataModel;
using IDocument = System.Qizx.Xdm.IDocument;
namespace System.Qizx.Api.Util
{
	
	/// <summary> Utility for conversion of an XMLPullStream input.
	/// <ul>
	/// <li>Conversion into a push stream: ({@link #convertTree} reads a portion
	/// of the input stream that form a complete element tree.
	/// <li>Building an in-memory Node representation: ({@link #buildNode}) reads
	/// a portion of the input stream that form a complete element and its subtree,
	/// or a leaf node, and builds a Node.
	/// </ul>
	/// </summary>
	public class PullStreamConverter
	{
		/// <summary> Reads events from the input stream until a complete well-balanced
		/// tree is sent to the output stream.
		/// Assumes that the current event points to the beginning of the tree.
		/// This method allows for incremental read of sub-trees. 
		/// </summary>
		/// <param name="in">an input stream of XML events
		/// </param>
		/// <param name="out">an output for XML events
		/// </param>
		/// <returns> the code of the event following the tree
		/// </returns>
		/// <throws>  DataModelException if thrown by the input stream </throws>
		public static int convertTree(XMLPullStream in_Renamed, XMLPushStream out_Renamed)
		{
			int e = in_Renamed.CurrentEvent;
			switch (e)
			{
				
				case System.Qizx.Api.XMLPullStream_Fields.DOCUMENT_START: 
					documentStart(in_Renamed, out_Renamed);
					e = in_Renamed.moveToNextEvent();
					for (; e != System.Qizx.Api.XMLPullStream_Fields.DOCUMENT_END && e != System.Qizx.Api.XMLPullStream_Fields.END; )
						convertTree(in_Renamed, out_Renamed);
					if (e == System.Qizx.Api.XMLPullStream_Fields.DOCUMENT_END)
					{
						out_Renamed.putDocumentEnd();
					}
					break;
				
				
				case System.Qizx.Api.XMLPullStream_Fields.ELEMENT_START: 
					elementStart(in_Renamed, out_Renamed);
					e = in_Renamed.moveToNextEvent();
					for (; e != System.Qizx.Api.XMLPullStream_Fields.ELEMENT_END && e != System.Qizx.Api.XMLPullStream_Fields.END; )
						e = convertTree(in_Renamed, out_Renamed);
					if (e == System.Qizx.Api.XMLPullStream_Fields.ELEMENT_END)
					{
						out_Renamed.putElementEnd(in_Renamed.Name);
					}
					break;
				
				
				case System.Qizx.Api.XMLPullStream_Fields.TEXT: 
					out_Renamed.putText(in_Renamed.Text);
					break;
				
				
				case System.Qizx.Api.XMLPullStream_Fields.PROCESSING_INSTRUCTION: 
					out_Renamed.putProcessingInstruction(in_Renamed.Target, in_Renamed.Text);
					break;
				
				
				case System.Qizx.Api.XMLPullStream_Fields.COMMENT: 
					out_Renamed.putComment(in_Renamed.Text);
					break;
				}
			// swallow something anyway:
			e = in_Renamed.moveToNextEvent();
			return e;
		}
		
		/// <summary> Directly builds an internal Node representation from a XML input stream.
		/// Reads exactly enough events to build a balanced tree.
		/// </summary>
		/// <param name="in">XML input stream
		/// </param>
		/// <returns> the Node built
		/// </returns>
		/// <throws>  DataModelException if thrown by the input stream </throws>
		public static Node buildNode(XMLPullStream in_Renamed)
		{
			IDocument doc;
			CorePushBuilder builder;
			
			int event_Renamed = in_Renamed.CurrentEvent;
			switch (event_Renamed)
			{
				
				case System.Qizx.Api.XMLPullStream_Fields.DOCUMENT_START: 
					doc = new IDocument();
					convertTree(in_Renamed, new PushStreamToSAX(doc));
					return new FONIDataModel(doc).DocumentNode;
				
				
				case System.Qizx.Api.XMLPullStream_Fields.ELEMENT_START: 
					doc = new IDocument();
					convertTree(in_Renamed, new PushStreamToSAX(doc));
					return new FONIDataModel(doc).DocumentNode;
				
				
				case System.Qizx.Api.XMLPullStream_Fields.TEXT: 
					builder = new CorePushBuilder(".");
					builder.putText(in_Renamed.Text);
					return builder.harvest();
				
				
				case System.Qizx.Api.XMLPullStream_Fields.PROCESSING_INSTRUCTION: 
					builder = new CorePushBuilder(".");
					builder.putProcessingInstruction(in_Renamed.Target, in_Renamed.Text);
					return builder.harvest();
				
				
				case System.Qizx.Api.XMLPullStream_Fields.COMMENT: 
					builder = new CorePushBuilder(".");
					builder.putComment(in_Renamed.Text);
					return builder.harvest();
				
				
				default: 
					return null;
				
			}
		}
		
		private PullStreamConverter()
		{
		}
		
		private static void  documentStart(XMLPullStream in_Renamed, XMLPushStream out_Renamed)
		{
			out_Renamed.putDocumentStart();
			string dtd = in_Renamed.DTDName;
			if (dtd != null)
				out_Renamed.putDTD(dtd, in_Renamed.DTDPublicId, in_Renamed.DTDSystemId, in_Renamed.InternalSubset);
		}
		
		private static void  elementStart(XMLPullStream in_Renamed, XMLPushStream out_Renamed)
		{
			out_Renamed.putElementStart(in_Renamed.Name);
			for (int n = 0, cnt = in_Renamed.NamespaceCount; n < cnt; n++)
			{
				out_Renamed.putNamespace(in_Renamed.getNamespacePrefix(n), in_Renamed.getNamespaceURI(n));
			}
			for (int a = 0, cnt = in_Renamed.AttributeCount; a < cnt; a++)
			{
				out_Renamed.putAttribute(in_Renamed.getAttributeName(a), in_Renamed.getAttributeValue(a), null);
			}
		}
	}
}